package us.gaaoc.framework.util.pdf;

/**
 * This is an utility class to determine coordinates to place an image
 * based on a text based target.
 */
import org.apache.log4j.Logger;
import org.pdfbox.exceptions.InvalidPasswordException;
import org.pdfbox.pdmodel.PDDocument;
import org.pdfbox.pdmodel.PDPage;

import org.pdfbox.util.Matrix;
import org.pdfbox.util.PDFTextStripper;
import org.pdfbox.util.TextPosition;

import us.gaaoc.framework.util.collections.FastGrowableIntArray;

import java.io.IOException;
import java.io.InputStream;

import java.util.List;

/**
 * This is a class to get X,Y coordinates of text and then find
 * the translated X,Y in User Space to place the image at.
 */
public class PDFTextTargetsUtility extends PDFTextStripper {
	
	/**
	 * char This is the target character to search for within the document.
	 */
	private char target;
	
	/**
	 * character array  This is the set of target characters to search for
	 */
	private char targets[];
	
	/**
	 * float array to keep track of temporary coordinates for X values
	 */
	private float tempX[];
	/**
	 * float array to keep track of temporary coordinates for Y values
	 */
	private float tempY[];
	/**
	 * float array to keep track of coordinates for X values of a specific 
	 * occurrence of a target.
	 */
	private float occurrenceX[];
	/**
	 * float array to keep track of coordinates for Y values of a specific 
	 * occurrence of a target.
	 */
	private float occurrenceY[];
	/**
	 * integer to keep track of location of array when searching for a string
	 */
	private int searchIndex;
	//private int searchIndex;
	/**
	 * integer to keep track of number of occurences of lead character within
	 * string being searched for
	 */
	private int leadCharOccurrences;
	/**
	 * integer array to keep track of where in the target string the occurences
	 * of the lead character reoccur.
	 */
	private int leadCharOccurrencesIndex[];
	/**
	 * Integer to keep track of number of characters past last target character
	 * found.  If more than 2 (for white space variation), restart search for 
	 * target string.  Since OCR requires flexibility in number of lines in 
	 * between target characters, this helps ensure that the lettering sequence
	 * is fairly contiguous.
	 */
	private int characterCountFromLastTarget = 0;

	/**
	 * Sets X coordinate where target is found
	 */
	private float x = 0;

	/**
	 * Sets Y coordinate where target is found
	 */
	private  float y = 0;

	/**
	 * Integer array to hold coordinates to be passed back to calling class.
	 */
	private  float coordinates[] = new float[2];

	/**
	 * Integer to hold page number on which the target was found
	 */
	private  int currentPageNumber = 0;
	/**
	 * Integer to hold page number of where latest target character was found.
	 */
	private  int pageWhereLatestTargetCharacterFound = 0;
	/**
	 * Integer to hold page number of where previous target character was found.
	 */
	private  int pageWherePreviousTargetCharacterFound = 0;
	/**
	 * Integer to keep track of last page number where target was found
	 */
	private  int lastPageNumber = 0;
	/**
	 * Integer to keep track of the last page of the document.
	 */
	private  int lastPageOfDocument = 0;
	/**
	 * Custom Integer Array to keep track of pages where target was found 
	 */
	private  FastGrowableIntArray pagesWhereTargetIsFound 
		= new FastGrowableIntArray();
	/**
	 * Multiple or Single Character Search Indicator
	 */
	private  Boolean multipleCharacterSearch = false;
	/**
	 * Indicator of whether to record first character or last character 
	 * coordinates for target use.  If set to true, then the first character's
	 * coordinates will be recorded.  If set to false, then the last character's
	 * coordinates will be recorded.  No effect on single character target 
	 * searches.
	 */
	private  Boolean startCharacterRecord = false;
	/**
	 * This indicates whether full target has been found or not.  If true, then 
	 * no need to look further.  If false, then continue on searching for 
	 * target.
	 */
	private  Boolean fullTargetFound = false;
	/**
	 * This indicates if the first or last occurence of the target is to be
	 * searched for.  True means that only the first occurence should be 
	 * recorded.  False means that the last occurence should be recorded.
	 */
	private  Boolean firstOccurrenceRecordIndicator = false;
	/** 
	 * This indicates if a specific occurrence of the target within the document 
	 * is to be recorded.  
	 */
	private  Boolean recordSpecificOccurrenceIndicator = false;
	/**
	 * This is a boolean to use if testing for a space character or white space
	 * as part of a string being used as a target.
	 */
	private  Boolean testingForSpace = false;
	/**
	 * This is an integer that indicates a specific occurrence to look for of 
	 * the target within the document. For example, record the 4th occurence of 
	 * the phrase "Sign Here".  By default, the first occurence is recorded.
	 */
	private  int occurrenceToRecord = 1;
	/**
	 * This is an integer to record the number of occurences found of the target
	 * within the document being searched.
	 */
	private  int occurrencesFound = 0;
	/**
	 * Log4J logger instance for this class
	 */
	private Logger LOG = Logger.getLogger(PDFTextTargetsUtility.class);

	/**
	 * Default constructor.
	 * 
	 * @throws IOException
	 *             If there is an error loading text stripper properties.
	 */
	public PDFTextTargetsUtility() throws IOException {
		// Sets sorting of text stream by display position
		super.setSortByPosition(true);
	}

	/**
	 * This will print the documents data.
	 * 
	 * @param target
	 *            The character target to search for within the PDF
	 * @param docToSearch
	 *            The PDF document stream to search
	 * @throws Exception
	 *             If there is an error parsing the document.
	 */
	public float[] findTextTargetCoordinates(char target,
			InputStream docToSearch) throws Exception {
		
		// Reset all coordinate holders
		resetForStartOfSearch();
		
		// Set target character
		setTarget(target);

		// Search the document for the target
		searchDocument(docToSearch);

		// Clean up flags for next run
		reset();
		// Return the coordinates found
		return coordinates;

	}

	/**
	 * Method to search PDF using a string of characters as a target instead of
	 * a single character.
	 * 
	 * @param targetString  String to search for in document
	 * @param docToSearch  Document to search within
	 * @param startCharacterRecordIndicator boolean of whether to look for first
	 * (true) or last (false) character coordinates
	 * @param recordFirstOccurenceOrLast boolean to indicate whether to record 
	 * the first occurence (true) or last occurrence (false)
	 * @return coordinates of the requested character
	 * @throws Exception
	 */
	public float[] findTextTargetCoordinates(String targetString,
			InputStream docToSearch, Boolean startCharacterRecordIndicator,
			Boolean recordFirstOccurenceOrLast)
			throws Exception {
		
		// Reset all coordinate holders
		resetForStartOfSearch();
		
		startCharacterRecord = startCharacterRecordIndicator;

		/*
		 * GOAL: Use a string as the target.
		 * 
		 * Steps: 
		 *    
		 * 		1) Convert target string to character array 
		 * 		2) Keep track of characters found from character array 
		 *  	3) Parse document to locate sequential characters 
		 *  	4) If correct sequence of characters present, target found, 
		 *  	else target not found, return error code of no 0,0 for 
		 *  	coordinates.
		 *  
		 *  	- Need a start marker 
		 *  	- Need to check for following characters on the same line 
		 *  		-- Can go to level of checking distance by font width, but
		 *  		to allow parsing to work with unknown font size, level of 
		 *  		granularity kept to if found on a single line.  Chances of
		 *  		target being found on single line without being the same 
		 *  		word can be avoided by choosing distinct words such as 
		 *  		names, field labels, etc and not using very simple 
		 *  		combinations of letters.  If desired, a fairly unique
		 *  		tag character can be used, such as a tilde or other special 
		 *  		character within or at the start or end of a target to 
		 *  		increase the uniqueness of the combination and decrease the
		 *  		chances of the target characters being found spread out in
		 *  		the same line.
		 *  	-Need to check to see of whole target is found and not just a 
		 *  	partial
		 * 
		 */
		
		
		// Set occurence to search for
		firstOccurrenceRecordIndicator = recordFirstOccurenceOrLast;
		// Set target character and array of subsequent characters
		char targetCharArray [] = targetString.toCharArray();
		
		setTargets(targetCharArray); // Array of subsequent characters
		setTarget(targets[0]); // Target character
		if(targetCharArray.length != 1) {
			// Set multiple character search indicator
			multipleCharacterSearch = true;
			// Determine how many occurences of the lead character are in the
			// string being searched for
			String stringToCount = new String(targets);
			leadCharOccurrences = countChars(stringToCount, targets[0]);
			// Search the document for the target
			searchDocument(docToSearch);
			// If target is found . . .
			if (occurrenceX != null) {
				// Pull out the desired character coordinates from the temp arrays
				if (startCharacterRecord) {
					coordinates[0] = occurrenceX[0];
					coordinates[1] = occurrenceY[1];
				} else if (!startCharacterRecord) {
					int arrayLength = occurrenceX.length - 1;
					coordinates[0] = occurrenceX[arrayLength];
					coordinates[1] = occurrenceY[arrayLength];
				}
			} else {
				// Set coordinates to 0, 0
				coordinates[0] = 0;
				coordinates[1] = 0;
			}
			reset();
		}else {
			// Set multiple character search indicator
			multipleCharacterSearch = false;
			this.findTextTargetCoordinates(targets[0], docToSearch);
		}
		//The following line is added by Frank
		reset();
		//End
		return coordinates;

	}
	/**
	 * Method to look for a specific occurence of a string as a target within
	 * a PDF document. For example, record the 4th occurence of 
	 * the phrase "Sign Here".  By default, the first occurence is recorded.
	 * 
	 * @param targetString - the string to search for
	 * @param docToSearch - the PDF document to search within
	 * @param startCharacterRecordIndicator Whether or not to record the 
	 * coordinates of the first or last character of the string
	 * @param occurrenceToSearchFor Integer number for which occurrence of the 
	 * string is being searched for.
	 * @return coordinates of the start or last character of the target string
	 * @throws Exception
	 */
	public float[] findTextTargetCoordinates(String targetString,
			InputStream docToSearch, Boolean startCharacterRecordIndicator,
			int occurrenceToSearchFor)
			throws Exception {
		// Reset all coordinate holders
		resetForStartOfSearch();
		startCharacterRecord = startCharacterRecordIndicator;
		// Set multiple character search indicator
		multipleCharacterSearch = true;
		// Set flag to record a specific occurrence of the target
		recordSpecificOccurrenceIndicator = true;
		// Set occurence to search for
		occurrenceToRecord = occurrenceToSearchFor;
		// Set target character and array of subsequent characters
		char targetCharArray [] = targetString.toCharArray();
		
		setTargets(targetCharArray); // Array of subsequent characters
		setTarget(targets[0]); // Target character
		// Determine how many occurences of the lead character are in the
		// string being searched for
		String stringToCount = new String(targets);
		leadCharOccurrences = countChars(stringToCount, targets[0]);
		// Search the document for the target
		searchDocument(docToSearch);
		// If target is found . . .
		if (occurrenceX != null) {
			// Pull out the desired character coordinates from the temp arrays
			if (startCharacterRecord) {
				coordinates[0] = occurrenceX[0];
				coordinates[1] = occurrenceY[1];
			} else if (!startCharacterRecord) {
				int arrayLength = occurrenceX.length - 1;
				coordinates[0] = occurrenceX[arrayLength];
				coordinates[1] = occurrenceY[arrayLength];
			}
		} else {
			// Set coordinates to 0, 0
			coordinates[0] = 0;
			coordinates[1] = 0;
		}
		// Clean up flags for next run
		reset();
		return coordinates;

	}

	/**
	 * An extended method provided as an event interface to allow a subclass to
	 * perform some specific functionality when a character needs to be
	 * displayed.
	 * 
	 * This extension looks for a particular character.
	 * 
	 * @param text
	 *            The character to be displayed.
	 */
	protected void showCharacter(TextPosition text) {
		
		
		
		/*
		 * If the text block is a single character, then the character needs to 
		 * be recorded if it starts a match of the initial target character. 
		 * Once recorded, the next target character is set as the target to look
		 * for.  If found on the same line, then proceed to replace the target 
		 * character with the next character from the targets array until the 
		 * whole target is found on the same line.  If not found on the same 
		 * line (not equal Y values), then restart over with initial character
		 * as the target value.  Once the last character has been found on the 
		 * same line, then the coordinates of this character are recorded and 
		 * are used to place the image.
		 * 
		 * If the initial character is found again before the next character to 
		 * search for is found, then restart over with the first character as 
		 * the initial target and proceed again searching for following 
		 * characters.
		 * 
		 * Need to count how many occurences of the initial character are in 
		 * target string.  If more than one, then need to compensate for finding
		 * multiples of the same character to not restart search all 
		 * over and to only record the coordinates of the initial character if 
		 * the first character coordinates are what is wanted.
		 * 
		 * Example:
		 * I. M. Attorney
		 * 
		 * I @ 122,456
		 * . @ 132,456
		 * M @ 142,456
		 * . @ 152,456
		 * 
		 * What structures are needed to implement:
		 *	* 3 arrays (size of string to search's length)
		 *  	** String to search
		 *   	** x float values
		 *   	** y float values
		 *  * 1 index integer - to keep track of location in search
		 *   
		 */
		
		// Get the string representation of the current text position
		String test = text.getCharacter();		
		if (multipleCharacterSearch == false) {
			/*
			 * The text position block is not always only a single character. To
			 * check for this occurence, if the string of the text is larger 
			 * than a single character, the following will loop through the 
			 * string to catch all occurences of the character.
			 */
			for (int i = 0; i < test.length(); i++) {
				if (text.getCharacter().charAt(i) == target) {
					// Get the text matrix to find the coordinates of the text 
					// in user space.
					Matrix gs = this.getTextMatrix();
					
					// Matrix tmTranslated = tm.getTranslatingInstance(x, y);
					recordCoordinates(gs);
					// Increment the number of occurrences found
					occurrencesFound++;
					// Record the page number where the target was found
					if (lastPageNumber != currentPageNumber 
							|| lastPageNumber == 0) {
						pagesWhereTargetIsFound.add(currentPageNumber);
						lastPageNumber = currentPageNumber;
					}
					LOG.debug("Current X, Y is: " + x + ", " + y);
				}
			}
		} else if (multipleCharacterSearch == true) {
			/*
			 * Perform extra processing to deal with checking multiple target 
			 * characters from a string.
			 */  	
			// Potentially process multiple characters in text position block
			int j = test.length();
			for (int i = 0; i < j; i++) { 
				// Count the characters being processed
				++characterCountFromLastTarget;
				// If initial character is found to signal a start of search
				// or if the next character to be searched for is found,
				// then record the x,y coordinates.
				char testCharacter = text.getCharacter().charAt(i);
				char targetAtIndex = targets[searchIndex];
				/*
				 * Perform a test to check to see if a space character or white
				 * space is part of the target string and the string being 
				 * searched at the same locations.  If it is, then set a flag
				 * since these two types of characters do not always pass the
				 * equality test when being compared to each other.
				 * 
				 * Note:  The first character of a target is assumed to not be
				 * either a space character or a white space character.
				 */
				if (Character.isSpaceChar(targetAtIndex) ||
						Character.isWhitespace(targetAtIndex)) {
					if (Character.isSpaceChar(testCharacter) ||
							Character.isWhitespace(testCharacter)) {
						testingForSpace = true;
					}
				}
				int targetLength = targets.length - 1;
				if (fullTargetFound == false || 
						firstOccurrenceRecordIndicator == false) {	
					/* Check to see if first character signalling to possibly
					 * start over, or if search index character to continue
					 * searching.  Also check to see if target is found fairly
					 * contiguously with previous target character.
					 */
					// If target is found . . .
					if ((testCharacter == targets[0] || 
						(testCharacter == targets[searchIndex] || testingForSpace)
						&& characterCountFromLastTarget <= 3) ) {
						// Work with recording of coordinates
						recordCoordinatesForString(this.getTextMatrix(), searchIndex);
						// Record where previous target character was found
						pageWherePreviousTargetCharacterFound 
							= pageWhereLatestTargetCharacterFound;
						// Record page where current target character is found
						pageWhereLatestTargetCharacterFound = currentPageNumber;
						// If full target is found . . .	
						if ((testCharacter == targets[searchIndex] 
						                              || testingForSpace) &&  
								targetLength == searchIndex) {
							fullTargetFound = true;
							// Increment the number of occurrences found
							occurrencesFound++;
							// Record the page number where the target was found
							if (lastPageNumber != currentPageNumber 
									|| lastPageNumber == 0) {
								pagesWhereTargetIsFound.add(currentPageNumber);
								lastPageNumber = currentPageNumber;
							}
							/* Check to see if first or another occurrence is 
							 * what is wanted.  If first, then once found, stop 
							 * looking to conserve processing. If last, then
							 * keep looking, but copy off last full match to 
							 * ensure that the coordinates are not partially 
							 * over written by a partial match.
							 */ 
							/*If this is the occurence being looked for then 
							 * record the coordinates.
							 */ 
							if (occurrenceToRecord == occurrencesFound &&
									recordSpecificOccurrenceIndicator == true) {
								recordOccurrenceCoordinates();
							}
							/*If this is the first occurence and it is being 
							 * looked for then record the coordinates.
							 */ 
							if (occurrencesFound == 1 && 
									firstOccurrenceRecordIndicator == true) {
								recordOccurrenceCoordinates();
							}
							/*If this is the first occurence and it is not being 
							 * looked for then record the coordinates of all
							 * occurrences.
							 */ 
							if (firstOccurrenceRecordIndicator == false && 
								   recordSpecificOccurrenceIndicator == false) {
								recordOccurrenceCoordinates();
							}
						}
						// Work with managing navigation through target search array
						if (fullTargetFound == false) {
							if (testCharacter == targets[0]) {
								if (searchIndex == 0) {
									searchIndex++;
								} else if ((testCharacter == targets[searchIndex]
								                                     || testingForSpace) && 
										searchIndex > 0 &&
										leadCharOccurrences > 0 &&
										characterCountFromLastTarget <= 3) {
									/* If on the same line as previous 
									 * character,  then increment search index 
									 * by 1
									 */
									float previousY = tempY[searchIndex - 1];
									float currentY = tempY[searchIndex];
									// TODO This is a temp solution to search within
									// 7 lines of the last found character and on 
									// the same page as the last character found
									float differenceOfYValues = currentY - previousY;
									if (differenceOfYValues < 700
										&& pageWhereLatestTargetCharacterFound 
											== pageWherePreviousTargetCharacterFound) {
										searchIndex++;
									}
								}
							} else if ((testCharacter == targets[searchIndex] 
							                                     || testingForSpace)) {
								/* If on the same line as previous character, 
								 * then increment search index by 1
								 */ 
								float currentY = tempY[searchIndex];
								float previousY; 
								if(searchIndex == 0)
								{
									previousY = tempY[searchIndex];
								}else{
									previousY = tempY[searchIndex - 1];
								}
								
								// TODO This is a temp solution to search within
								// 7 lines of the last found character and on 
								// the same page as the last character found
								float differenceOfYValues = currentY - previousY;
								if (differenceOfYValues < 700
									&& pageWhereLatestTargetCharacterFound 
											== pageWherePreviousTargetCharacterFound
									&& characterCountFromLastTarget < 3) {
										searchIndex++;
								} else {
									/* Else, rest not found on same line, so 
									 * start search over.
									 */
									searchIndex = 0;
								}
							}
						} else if (fullTargetFound == true && 
								firstOccurrenceRecordIndicator == false) {
							// Reset full target found indicator for next
							// run
							fullTargetFound = false;
							// Reset search index
							searchIndex = 0;
						} 
						
						// Reset counter since a new target character
						// has been found.
						characterCountFromLastTarget = 0;
						// Reset Testing For Space boolean
						testingForSpace = false;
						
					} else if (characterCountFromLastTarget > 4) {
						/*
						 * If been more than 4 since last character found,
						 * restart search. 
						 */  
						
						searchIndex = 0;
						characterCountFromLastTarget = 0;
					}
				}
				
		
			}
		
		}
		
	}
	

	/**
	 * Method to record coordinates for a single character or block of text.
	 * @param gs
	 */
	private void recordCoordinates(Matrix gs) {
		x = gs.getXPosition();
		y = gs.getYPosition();
		if (coordinates == null) {
			coordinates = new float[2];
		}
		coordinates[0] = x;
		coordinates[1] = y;
	}
	/**
	 * Method to record coordinates of characters in a string
	 * @param gs
	 * @param index
	 */
	private void recordCoordinatesForString(Matrix gs, int index) {
		int storageIndex = index;
		float tempXCoord = gs.getXPosition();
		float tempYCoord = gs.getYPosition();
		// Initialize arrays if not already initialized
		if (tempX == null && tempY == null) {
			tempX = new float[targets.length];
			tempY = new float[targets.length];
		}
		tempX[storageIndex] = tempXCoord;
		tempY[storageIndex] = tempYCoord;
	}
	
	private void recordOccurrenceCoordinates() {
		if (occurrenceX == null && occurrenceY == null) {
			occurrenceX = new float[tempX.length];
			occurrenceY = new float[tempY.length];
		}
		occurrenceX = (float[]) tempX.clone();  // Copy X coordinates
		occurrenceY = (float[]) tempY.clone();  // Copy Y coordinates	
	}
	
	/**
	 * Utility method to count the number of characters occurring in a string.
	 * @param s - string to search
	 * @param c - character to search for
	 * @return number of characters searched for that were found in the string
	 */
	public int countChars(String s, char c) {
		int numberOfChars = 0;
		char ca[] = s.toCharArray();
		int arrayLength = ca.length;
		// Record the number of occurences of the character
		for (int i = 0; i < arrayLength; i++) {
			if (ca[i] == c) {
				numberOfChars++;
			}
		}
		// If the character is present . . .
		if (numberOfChars > 0) {
			// Record where in the string those occurences of the character are
			for (int i = 0; i < numberOfChars; i++) {
				// Initialize the array for current context
				leadCharOccurrencesIndex = new int[numberOfChars];
				/* Record the index of the character, remove that portion of the
				 * string, move on to the next occurence of the character.
				 */ 
				leadCharOccurrencesIndex[i] = s.indexOf(c);
				s.substring((leadCharOccurrencesIndex[i] + 1));
			}
		}
		return numberOfChars;
	}

	/**
	 * @return the target
	 */
	public  char getTarget() {
		return target;
	}

	/**
	 * @param target
	 *            the target to set
	 */
	public  void setTarget(char target) {
		this.target = target;
	}
	
	/**
	 * @return the targets
	 */
	public  char[] getTargets() {
		return targets;
	}

	/**
	 * @param targets the targets to set
	 */
	public  void setTargets(char[] targets) {
		this.targets = targets;
	}

	/**
	 * @return the x
	 */
	public  float getX() {
		return x;
	}

	/**
	 * @param x
	 *            the x to set
	 */
	public  void setX(float x) {
		this.x = x;
	}

	/**
	 * @return the y
	 */
	public  float getY() {
		return y;
	}

	/**
	 * @param y
	 *            the y to set
	 */
	public  void setY(float y) {
		this.y = y;
	}

	/**
	 * @return the currentPageNumber
	 */
	public int getCurrentPageNumber() {
		return currentPageNumber;
	}

	/**
	 * @param currentPageNumber
	 *            the currentPageNumber to set
	 */
	public void setCurrentPageNumber(
			int pageNumberOfLastTargetFound) {
		currentPageNumber = pageNumberOfLastTargetFound;
	}

	/**
	 * @return an array containing where in the string the lead character
	 * reoccurs, if it reoccurs.
	 */
	public int[] getLeadCharOccurrencesIndex() {
		return leadCharOccurrencesIndex;
	}
	
	/**
	 * Method to perform parsing of document and to start search for target 
	 * within the document.
	 * 
	 * @param docToSearch An input stream of the document to be searched
	 * @throws Exception An I/O exception if there are problems reading the 
	 * file.
	 */
	@SuppressWarnings("unchecked")
	private void searchDocument(InputStream docToSearch) 
		throws Exception {
		PDDocument document = null;
		try {
			document = PDDocument.load(docToSearch);
			if (document.isEncrypted()) {
				try {
					document.decrypt("");
				} catch (InvalidPasswordException e) {
					System.err
							.println("Error: Document is encrypted with a password.");
					//System.exit(1);
				}
			}
			// Find the target in the document
			//PDFTextTargetsUtility printer = new PDFTextTargetsUtility();

			List allPages = document.getDocumentCatalog().getAllPages();
			int numberOfPages = allPages.size();
			// Record the number of pages of document
			lastPageOfDocument = numberOfPages;
			for (int i = 0; i < numberOfPages; i++) {
				// Record the page being searched currently
				currentPageNumber = i + 1;
				PDPage page = (PDPage) allPages.get(i);
				/*
				 * Stream through the PDF searching for the target character
				 * by character.
				 */ 
				processStream(page, page.findResources(), page
						.getContents().getStream());	
			}
		} finally {
			if (document != null) {
				document.close();
			}
		}
	}
	/**
	 * This is a method to perform clean up on internal flags and variables
	 * for this class.
	 */
	private void reset(){
		// Reset full target found indicator
		fullTargetFound = false;
		// Reset multiple character search indicator
		multipleCharacterSearch = false;
		// Reset start character coordinate recording indicator
		startCharacterRecord = false;
		// Reset first occurrence indicator
		firstOccurrenceRecordIndicator = false;
		// Reset the specific occurrence indicator
		recordSpecificOccurrenceIndicator = false;
		// Reset occurrence coordinates to record
		occurrenceToRecord = 1;
		// Reset occurrences found
		occurrencesFound = 0;
		// Reset Search Index 
		searchIndex = 0;
		// Reset Count of Lead Characters
		leadCharOccurrences = 0;
		currentPageNumber = 0;
		lastPageNumber = 0;
		characterCountFromLastTarget = 0;
		pageWhereLatestTargetCharacterFound = 0;
		pageWherePreviousTargetCharacterFound = 0;
		
	}
	/**
	 * This is a method to reset all coordinate holding variables before 
	 * performing a new search.
	 */
	private void resetForStartOfSearch() {
		// Reset target to look for
		targets = null;
		// Reset Coordinates
		tempX = null;
		tempY = null;
		occurrenceX = null;
		occurrenceY = null;
		coordinates = new float[2];
		// Reset count of lead character occurences
		leadCharOccurrencesIndex = null;
		// Reset holder for page numbers where target is located
		pagesWhereTargetIsFound = new FastGrowableIntArray();
	}

	/**
	 * @return the pagesWhereTargetIsFound
	 */
	public int[] getPagesWhereTargetIsFound() {
		return pagesWhereTargetIsFound.toArray();
	}

	/**
	 * @param pagesWhereTargetIsFound the pagesWhereTargetIsFound to set
	 */
	public void setPagesWhereTargetIsFound(
			FastGrowableIntArray pagesWhereTargetIsFound) {
		pagesWhereTargetIsFound = pagesWhereTargetIsFound;
	}
	/**
	 * @return the lastPageOfDocument
	 */
	public int getLastPageOfDocument() {
		return lastPageOfDocument;
	}

}